package com.jcark.ui.view.textview

import android.annotation.SuppressLint
import android.content.Context
import android.graphics.Canvas
import android.graphics.Paint
import android.graphics.Rect
import android.graphics.drawable.Drawable
import android.graphics.drawable.GradientDrawable
import android.os.Build
import android.util.AttributeSet
import android.widget.TextView
import androidx.annotation.ColorInt
import com.jcark.ui.R
import com.jcark.ui.font.FontManager
import com.jcark.ui.utils.RoundCornerProvider

@SuppressLint("AppCompatCustomView")
open class MTextView : TextView {
    private var mTypeFaceValue = 0
    private var mRadius = 0
    private var mBackgroundStrokeWidth = 0
    private var mBackgroundStrokeColor = 0
    private var mBackgroundColor = 0
    private var mIsRefreshMeasure = false
    private var mIsRemoveSpace = false
    private val mStrokeWidthValue = -1f
    private var typefaceArray =
        arrayListOf<Int>(Thin, ExtraLight, Light, Regular, Medium, SemiBold, Bold, ExtraBold, Black)

    private var mFontWeight = -1

    constructor(context: Context?) : super(context) {}

    init {
        includeFontPadding = false
    }

    companion object {
        const val Thin = 4
        const val ExtraLight = 5
        const val Light = 6
        const val Regular = 7
        const val Medium = 8
        const val SemiBold = 9
        const val Bold = 10
        const val ExtraBold = 11
        const val Black = 12
    }

    @JvmOverloads
    constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int = 0) : super(
        context,
        attrs,
        defStyleAttr
    ) {
        val typedArray = context.obtainStyledAttributes(attrs, R.styleable.MTextView)
        mTypeFaceValue = typedArray.getInt(R.styleable.MTextView_mtv_external_typeface, 0)
        mFontWeight = typedArray.getInt(R.styleable.MTextView_mtv_external_font_weight, -1)
        if (mFontWeight > 3) {
            mTypeFaceValue = mFontWeight
        }
        mRadius = typedArray.getDimensionPixelSize(R.styleable.MTextView_mtv_external_radius, 0)
        mBackgroundStrokeWidth =
            typedArray.getDimensionPixelSize(R.styleable.MTextView_mtv_background_stroke_width, 0)
        mBackgroundStrokeColor =
            typedArray.getColor(R.styleable.MTextView_mtv_background_stroke_color, -1)
        mBackgroundColor =
            typedArray.getColor(R.styleable.MTextView_mtv_background_color, -1)
        mIsRemoveSpace = typedArray.getBoolean(R.styleable.MTextView_mtv_remove_space, false)
        init(context)
        typedArray.recycle()
    }

    override fun setText(text: CharSequence, type: BufferType) {
        super.setText(text, type)
        // 每次文本内容改变时，需要测量两次，确保计算的高度没有问题
        mIsRefreshMeasure = true
    }

    override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec)
        if (mIsRemoveSpace) {
            removeSpace(widthMeasureSpec, heightMeasureSpec)
        }
    }

    /**
     * 这里处理文本的上下留白问题
     */
    private fun removeSpace(widthSpace: Int, heightSpace: Int) {
        val paddingTop: Int
        val linesText = linesText
        val paint = paint
        val rect = Rect()
        val text = linesText[0]
        paint.getTextBounds(text, 0, text!!.length, rect)
        val fontMetricsInt = Paint.FontMetricsInt()
        paint.getFontMetricsInt(fontMetricsInt)
        paddingTop = fontMetricsInt.top - rect.top

        // 设置TextView向上的padding (小于0, 即把TextView文本内容向上移动)
        setPadding(
            leftPaddingOffset,
            paddingTop + topPaddingOffset,
            rightPaddingOffset,
            bottomPaddingOffset
        )
        val endText = linesText[linesText.size - 1]
        paint.getTextBounds(endText, 0, endText!!.length, rect)

        // 再减去最后一行文本的底部空白，得到的就是TextView内容上线贴边的的高度，到达消除文本上下留白的问题
        setMeasuredDimension(measuredWidth, measuredHeight - (fontMetricsInt.bottom - rect.bottom))
        if (mIsRefreshMeasure) {
            mIsRefreshMeasure = false
            measure(widthSpace, heightSpace)
        }
    }//指定行的内容

    /**
     * 获取每一行的文本内容
     */
    private val linesText: Array<String?>
        private get() {
            var start = 0
            var end: Int
            val texts = arrayOfNulls<String>(lineCount)
            val text = text.toString()
            val layout = layout
            for (i in 0 until lineCount) {
                end = layout.getLineEnd(i)
                //指定行的内容
                val line = text.substring(start, end)
                start = end
                texts[i] = line
            }
            return texts
        }

    /**
     * 初始化
     *
     * @param context 上下文
     */
    private fun init(context: Context) {
        if (mBackgroundStrokeWidth > 0) {
            setBackgroundStrokeDrawable(
                context, mBackgroundColor, mBackgroundStrokeColor, mBackgroundStrokeWidth,
                GradientDrawable.RECTANGLE, mRadius.toFloat()
            )
        } else {
            //不设置背景时才单独设置圆角
            if (mRadius > 0) {
                setRoundCorner(mRadius.toFloat())
            }
        }
        if (mTypeFaceValue !in typefaceArray) {
            FontManager.getInstance().setTypeface(context, this, mTypeFaceValue)
        }
        setLineSpacing(dpToPx(context, 1.5f).toFloat(), 1f)
    }

    override fun onDraw(canvas: Canvas) {
        if (mTypeFaceValue in typefaceArray) {
            when (mTypeFaceValue) {
                Thin -> paint.strokeWidth = 0.4f //100
                ExtraLight -> paint.strokeWidth = 0.5f //200
                Light -> paint.strokeWidth = 0.6f //300
                Regular -> paint.strokeWidth = 0.0f //400
                Medium -> paint.strokeWidth = 0.8f //500
                SemiBold -> paint.strokeWidth = 1f //600
                Bold -> paint.strokeWidth = 1.2f //700
                ExtraBold -> paint.strokeWidth = 1.3f //800
                Black -> paint.strokeWidth = 2f //900
            }
            paint.style = Paint.Style.FILL_AND_STROKE
        }

        super.onDraw(canvas)
    }

    fun setTextStyleType(typeFaceValue: Int) {
        mTypeFaceValue = typeFaceValue
        super.setTypeface(typeface)
        postInvalidate()
    }

    /**
     * 设置圆角
     *
     * @param radius 圆角大小
     */
    fun setRoundCorner(radius: Float) {
        if (radius > 0 && Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            clipToOutline = true
            outlineProvider = RoundCornerProvider(radius)
        }
    }

    /**
     * 设置边框背景
     *
     * @param context     上下文
     * @param strokeColor 边框颜色
     * @param strokeWidth 边框宽度 px
     * @param share       形状，取值参考[GradientDrawable]
     * @param radius      圆角大小
     */
    fun setBackgroundStrokeDrawable(
        context: Context,
        @ColorInt backgroundColor: Int,
        @ColorInt strokeColor: Int,
        strokeWidth: Int,
        share: Int,
        radius: Float
    ) {
        background = getBackgroundStrokeDrawable(
            context,
            backgroundColor,
            strokeColor,
            strokeWidth,
            share,
            radius
        )
    }

    /**
     * 生成边框背景
     *
     * @param context     上下文
     * @param strokeColor 边框颜色
     * @param strokeWidth 边框宽度 px
     * @param share       形状，取值参考[GradientDrawable]
     * @param radius      圆角大小
     * @return 返回背景
     */
    private fun getBackgroundStrokeDrawable(
        context: Context,
        @ColorInt backgroundColor: Int,
        @ColorInt strokeColor: Int,
        strokeWidth: Int,
        share: Int,
        radius: Float
    ): Drawable {
        val drawable = GradientDrawable()
        drawable.setStroke(strokeWidth, strokeColor)
        drawable.cornerRadius = dpToPx(context, radius).toFloat()
        drawable.shape = share
        drawable.setColor(backgroundColor)
        return drawable
    }

    private fun dpToPx(context: Context, value: Float): Int {
        val scale = context.resources.displayMetrics.density
        return (value * scale + 0.5f).toInt()
    }
}